﻿using System;
using System.Collections.Generic;
using AccessControl.Wpf.ViewModels;
using AccessControl.Contracts.Models;
using System.Collections.ObjectModel;
using System.Windows.Input;
using AccessControl.Contracts.Reports;
using AccessControl.Contracts.Settings;
using AccessControl.Wpf.Commands;
using System.Net.Mail;
using System.Threading;
using System.Windows.Threading;
using AccessControl.Wpf.Converters;
using System.Net;

namespace AccessControl.Wpf.Reports.ViewModels
{
	class ReportsViewModel : ViewModel, IActionViewModel
	{
		#region Fields

		private int _MailServerPort = 25;
		private IReportsService _ReportsService;
		private ISettingsService _SettingsService;
		private DateTime _StartDate = DateTime.Now, _EndDate = DateTime.Now;
		private bool _IsInSendMailState, _IsMailNeedsAuthentication, _IsInProccessOfSendMail;
		private TimeSpan _StartTime = DateTime.Now.TimeOfDay, _EndTime = DateTime.Now.TimeOfDay;
		private ObservableCollection<IEntry> _SelectedEntries = new ObservableCollection<IEntry>();
		private string _MailServerAddress, _MailFromAddress, _MailUserName, _MailPassword, _MailRecipients;
		private static SensorToRelatedEntryConverter _sensorToRelatedEntryConverter = new SensorToRelatedEntryConverter();
		private static readonly DispatcherSynchronizationContext _synchronizationContext = new DispatcherSynchronizationContext();

		#endregion

		public ReportsViewModel(IReportsService reportsService, ISettingsService settingsService)
		{
			ReportsService = reportsService;
			SettingsService = settingsService;
		}

		#region Public Properties

		public IReportsService ReportsService
		{
			get { return _ReportsService; }
			private set
			{
				if (_ReportsService != value)
				{
					_ReportsService = value;
					NotifyPropertyChanged("ReportsService");
				}
			}
		}

		public ISettingsService SettingsService
		{
			get { return _SettingsService; }
			private set
			{
				if (_SettingsService != value)
				{
					_SettingsService = value;
					NotifyPropertyChanged("SettingsService");
				}
			}
		}

		public DateTime StartDate
		{
			get { return _StartDate; }
			set
			{
				if (_StartDate != value)
				{
					_StartDate = value;
					NotifyPropertyChanged("StartDate");
				}
			}
		}

		public TimeSpan StartTime
		{
			get { return _StartTime; }
			set
			{
				if (_StartTime != value)
				{
					_StartTime = value;
					NotifyPropertyChanged("StartTime");
				}
			}
		}

		public DateTime EndDate
		{
			get { return _EndDate; }
			set
			{
				if (_EndDate != value)
				{
					_EndDate = value;
					NotifyPropertyChanged("EndDate");
				}
			}
		}

		public TimeSpan EndTime
		{
			get { return _EndTime; }
			set
			{
				if (_EndTime != value)
				{
					_EndTime = value;
					NotifyPropertyChanged("EndTime");
				}
			}
		}

		public IList<IEntry> SelectedEntries
		{
			get { return _SelectedEntries; }
		}

		public bool IsInSendMailState
		{
			get { return _IsInSendMailState; }
			set
			{
				if (_IsInSendMailState != value)
				{
					_IsInSendMailState = value;
					NotifyPropertyChanged("IsInSendMailState");
				}
			}
		}

		public bool IsMailNeedsAuthentication
		{
			get { return _IsMailNeedsAuthentication; }
			set
			{
				if (_IsMailNeedsAuthentication != value)
				{
					_IsMailNeedsAuthentication = value;
					NotifyPropertyChanged("IsMailNeedsAuthentication");
				}
			}
		}

		public string MailServerAddress
		{
			get { return _MailServerAddress; }
			set
			{
				if (_MailServerAddress != value)
				{
					_MailServerAddress = value;
					NotifyPropertyChanged("MailServerAddress");
				}
			}
		}

		public int MailServerPort
		{
			get { return _MailServerPort; }
			set
			{
				if (_MailServerPort != value)
				{
					_MailServerPort = value;
					NotifyPropertyChanged("MailServerPort");
				}
			}
		}
		
		public string MailFromAddress
		{
			get { return _MailFromAddress; }
			set
			{
				if (_MailFromAddress != value)
				{
					_MailFromAddress = value;
					NotifyPropertyChanged("MailFromAddress");
				}
			}
		}

		public string MailUserName
		{
			get { return _MailUserName; }
			set
			{
				if (_MailUserName != value)
				{
					_MailUserName = value;
					NotifyPropertyChanged("MailUserName");
				}
			}
		}

		public string MailPassword
		{
			get { return _MailPassword; }
			set
			{
				if (_MailPassword != value)
				{
					_MailPassword = value;
					NotifyPropertyChanged("MailPassword");
				}
			}
		}

		public string MailRecipients
		{
			get { return _MailRecipients; }
			set
			{
				if (_MailRecipients != value)
				{
					_MailRecipients = value;
					NotifyPropertyChanged("MailRecipients");
				}
			}
		}

		public bool IsInProccessOfSendMail
		{
			get { return _IsInProccessOfSendMail; }
			set
			{
				if (_IsInProccessOfSendMail != value)
				{
					_IsInProccessOfSendMail = value;
					NotifyPropertyChanged("IsInProccessOfSendMail");
				}
			}
		}
		
		
		
		#endregion

		#region Commands

		public ICommand GenerateReportCommand
		{
			get { return new CommandBase(GenerateReport); }
		}

		public ICommand ClearListCommand
		{
			get { return new CommandBase(ClearList); }
		}

		public ICommand PrintCommand
		{
			get { return null; }
		}

		public ICommand SendByMailCommand
		{
			get { return new CommandBase(SendByMail); }
		}

		public ICommand SelectEntryCommand
		{
			get { return new CommandBaseOfT<IEntry>(SelectEntry); }
		}

		public ICommand DeselectEntryCommand
		{
			get { return new CommandBaseOfT<IEntry>(DeselectEntry); }
		}

		public ICommand SetSendMailStateCommand
		{
			get { return new CommandBase(SetSendMailState); }
		}

		public ICommand UnsetSendMailStateCommand
		{
			get { return new CommandBase(UnsetSendMailState); }
		}

		#endregion

		#region IActionViewModel Members

		public Contracts.Models.Action ViewModelAction
		{
			get { return Contracts.Models.Action.Reports; }
		}

		#endregion

		#region Private Members

		private void SelectEntry(IEntry entry)
		{
			if (!SelectedEntries.Contains(entry))
				SelectedEntries.Add(entry);
		}

		private void DeselectEntry(IEntry entry)
		{
			if (SelectedEntries.Contains(entry))
				SelectedEntries.Remove(entry);
		}

		private void GenerateReport()
		{
			if (SelectedEntries.Count == 0)
			{
				MessagingService.Show("No entry was selected. Please select entry for the report", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
				return;
			}

			DateTime startTime = new DateTime(StartDate.Year, StartDate.Month, StartDate.Day, StartTime.Hours, StartTime.Minutes, StartTime.Seconds);
			DateTime endTime = new DateTime(EndDate.Year, EndDate.Month, EndDate.Day, EndTime.Hours, EndTime.Minutes, EndTime.Seconds);

			if (startTime > endTime)
			{
				MessagingService.Show("Invalid times selected", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
				return;
			}

			if (SelectedEntries.Count == 0)
				ReportsService.Events.LoadEvents(startTime, endTime);
			else
				ReportsService.Events.LoadEvents(startTime, endTime, SelectedEntries);

            if (ReportsService.Events.Items.Count == 0)
            {
                MessagingService.Show("No events found in the spcific time range", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Information);
                return;
            }
		}

		private void ClearList()
		{
			ReportsService.Events.Items.Clear();
		}

		private void SetSendMailState()
		{
			IsInSendMailState = true;
		}

		private void UnsetSendMailState()
		{
			IsInSendMailState = false;
		}

		private void SendByMail()
		{
			int portNumber;
			string [] recipients;

			/* Validate the events */
			if (ReportsService.Events.Items.Count == 0)
			{
				MessagingService.Show("No events in the list", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
				return;
			}

			/* Validate the server address */
			if (string.IsNullOrEmpty(MailServerAddress))
			{
				MessagingService.Show("Invalid mail server address", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
				return;
			}

			/* Validate the port number */
			if (MailServerPort <= 0)
			{
				MessagingService.Show("Invalid mail server port", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
				return;
			}

			/* Validate the user name and password */
			if (IsMailNeedsAuthentication && string.IsNullOrEmpty(MailUserName))
			{
				MessagingService.Show("Invalid user name", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
				return;
			}

			/* Validate the sender address */
			if (IsMailNeedsAuthentication && string.IsNullOrEmpty(MailUserName))
			{
				MessagingService.Show("Invalid user name", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
				return;
			}

			if (string.IsNullOrEmpty(MailRecipients))
			{
				MessagingService.Show("No recipient entered", "AccessControl", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Exclamation);
				return;
			}

			/* All operation is done in the dedicated thread */
			new Thread(new ThreadStart(SendEventsByMail)) { IsBackground = true }.Start();			
		}

		private void SendEventsByMail()
		{
			IEvent myEvent;
			SmtpClient client;
			string [] recipients;
			string  messageString = string.Empty;

			/* First of all */
			_synchronizationContext.Send(delegate { IsInProccessOfSendMail = true; }, null);
			/* Create the smtp client */
			try		
			{ 
				client = new SmtpClient(MailServerAddress, MailServerPort); 
			}
			catch 
			{ 
				_synchronizationContext.Send(delegate { IsInProccessOfSendMail = false; }, null);
				return;
			}

			if (IsMailNeedsAuthentication)
				client.Credentials = new NetworkCredential(MailUserName, MailPassword);
			/* Create the message string */
			for (int i = 0; i < ReportsService.Events.Items.Count; ++i)
			{
				myEvent = ReportsService.Events.Items[i];
				messageString += string.Format("{0}: ", i + 1);
				messageString += string.Format("Entry name: {0}{1}", _sensorToRelatedEntryConverter.Convert(myEvent.AssociatedSensor, null, "Name", null), Environment.NewLine);
				messageString += string.Format("Time: {0}{1}", myEvent.EventTime, Environment.NewLine);
				messageString += string.Format("Raised by sensor: {0}{1}", myEvent.AssociatedSensor.Type, Environment.NewLine);
				messageString += string.Format("Handled: {0}{1}", myEvent.Handled, Environment.NewLine);
				messageString += string.Format("Handling operator: {0}{1}{1}", myEvent.HandlingOperator, Environment.NewLine);
			}

			recipients = MailRecipients.Split(';');
			foreach (string recipient in recipients)
			{
				try
				{
					MailAddress address = new MailAddress(recipient, MailFromAddress);
					MailMessage message = new MailMessage(new MailAddress(MailFromAddress), address)
					{
						Subject = "Events report from Access Control system",
						Body = messageString
					};

					client.Send(message);
				}
				catch { }
			}
			
			/* And we are done */
			_synchronizationContext.Send(delegate { IsInProccessOfSendMail = false; }, null);
		}

		#endregion
	}
}
